/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#include "StdAfx.h"
#include "MPortDescriptionList.h"

#include <algorithm>

//---------------------------------------------------------------------------

MPortDescriptionList::MPortDescriptionList(void) : MFileConfig()
{
	loadFromIana = false;
}

MPortDescriptionList::~MPortDescriptionList(void)
{
	CleanUp();
}

//---------------------------------------------------------------------------

void MPortDescriptionList::CleanUp(void)
{
	MPortDescription *elem;

	for(iter=theVector.begin(); iter!=theVector.end(); iter++){
		elem = *iter;
		if(elem!=NULL){
			*iter = NULL;
			delete elem;
		}
	}
	theVector.clear();
}

//---------------------------------------------------------------------------

MPortDescription* MPortDescriptionList::CreateElement(void)
{
	MPortDescription* elem;

	try{
		elem = new MPortDescription;
	}
	catch(...){
		elem = NULL;
	}
	
	return elem;
}

//---------------------------------------------------------------------------

MPortDescription* MPortDescriptionList::FindElement(MPortDescription* elemIn)
{
	MPortDescription* elem;
	MPortDescription* res;

	if(elemIn==NULL) return NULL;

	res = NULL;
	for(iter=theVector.begin(); iter!=theVector.end() && res==NULL; iter++){
		elem = *iter;
		if(elem!=NULL){
			if(elem->IsEqualWith(elemIn))
				res = elem;
		}
	}

	return res;
}

MPortDescription* MPortDescriptionList::FindElementByPortAndProtocol(MPortDescription* elemIn)
{
	MPortDescription* elem;
	MPortDescription* res;

	if(elemIn==NULL) return NULL;

	res = NULL;
	for(iter=theVector.begin(); iter!=theVector.end() && res==NULL; iter++){
		elem = *iter;
		if(elem!=NULL){
			if(elem->xPort==elemIn->xPort)
				if(elem->xProto==elemIn->xProto)
					res = elem;
		}
	}

	return res;
}

//---------------------------------------------------------------------------

bool MPortDescriptionList::Add(MPortDescription* elemIn)
{
	MPortDescription* elem;
	int cnt;

	if(elemIn==NULL) return true;	// nothing to add

	elem = CreateElement();
	if(elem==NULL) return false;

	elem->LoadFromPointer(elemIn);

	cnt = (int)theVector.size();
	theVector.insert(theVector.begin(), elem);
	cnt = (int)theVector.size() - cnt;
	if(cnt!=1){
		delete elem;
		return false;
	}

	return true;
}

bool MPortDescriptionList::AddNoDuplicates(MPortDescription* elemIn)
{
	MPortDescription* elem;
	int pos;

	elem = FindElementByPortAndProtocol(elemIn);
	if(elem==NULL)
		return Add(elemIn);

	if(elemIn->xName.IsEmpty())
		return false;
	if(elemIn->xProto==0)
		return false;

	// a new server on the same port and protocol ?
	pos = elem->xName.Find(elemIn->xName);
	if(pos<0){
		// name not added, add it now
		elem->xName += _T(", ");
		elem->xName += elemIn->xName;
	}

	return true;
}

void MPortDescriptionList::Clear(void)
{
	CleanUp();
}

//---------------------------------------------------------------------------

int MPortDescriptionList::GetSize(void)
{
	return (int)theVector.size();
}

MPortDescription* MPortDescriptionList::GetByIdx(int idxIn)
{
	if(idxIn<0)          return NULL;
	if(idxIn>=GetSize()) return NULL;

	return theVector[idxIn];
}

//---------------------------------------------------------------------------

bool MPortDescriptionGreater(MPortDescription* a1, MPortDescription* a2)
{
	if(a2==NULL) return true;
	if(a1==NULL) return false;

	if(a1->xProto < a2->xProto) return true;
	if(a1->xProto > a2->xProto) return false;
	
	return a1->xPort < a2->xPort;
}

void MPortDescriptionList::SortTheList(void)
{
	std::sort(theVector.begin(), theVector.end(), MPortDescriptionGreater);
}

//---------------------------------------------------------------------------

void MPortDescriptionList::InternalInit(void)
{
	CleanUp();
}

bool MPortDescriptionList::InternalProcessIANALine(char* strIn)
{
	CString str, strL, strR, strName, strPort, strType, strDesc;
	MPortDescription mpd;
	int pos;

	str = strIn;

	str = str.Trim();

	pos = str.Find(_T("/"));
	if(pos<0){
		MessageBox(AfxGetMainWnd()->m_hWnd, str, _T("Import error"), MB_OK | MB_ICONSTOP);
		return false;
	}
	strL = str.Left(pos);
	strR = str.Mid(pos + 1);
	strL = strL.Trim();
	strR = strR.Trim();

	pos = strL.FindOneOf(_T(" \t"));
	if(pos<0){
		strName.Empty();
		strPort = strL;
	}
	else{
		strName = strL.Left(pos);
		strPort = strL.Mid(pos + 1);
	}
	strName = strName.Trim();
	strPort = strPort.Trim();

	pos = strR.FindOneOf(_T(" \t"));
	if(pos<0){
		strType = strR;
		strDesc.Empty();
	}
	else{
		strType = strR.Left(pos);
		strDesc = strR.Mid(pos + 1);
	}
	strType = strType.Trim();
	strDesc = strDesc.Trim();

	if(strName.IsEmpty()) strName = strDesc;
	if(strName.IsEmpty()){
		str = strIn;
		MessageBox(AfxGetMainWnd()->m_hWnd, str, _T("Import error"), MB_OK | MB_ICONSTOP);
		return false;
	}

	mpd.xPort  = _tstoi(strPort);

	if(strName.CompareNoCase(_T("clxxx1"))==0)
		strName = _T("cl/1");
	if(strName.CompareNoCase(_T("914cxxxg"))==0)
		strName = _T("914c/g");

	mpd.xName  = strName;

	if(strType.CompareNoCase(_T("SCTP"))==0){
		// I do not need this
		return true;
	}

	mpd.xProto = 0;
	if(strType.CompareNoCase(_T("TCP"))==0) mpd.xProto += (WORD)__mpdpTcp;
	if(strType.CompareNoCase(_T("UDP"))==0) mpd.xProto += (WORD)__mpdpUdp;
	if(mpd.xProto==0){
		str = strIn;
		MessageBox(AfxGetMainWnd()->m_hWnd, str, _T("Import error"), MB_OK | MB_ICONSTOP);
		return false;
	}

	return AddNoDuplicates(&mpd);
}

bool MPortDescriptionList::InternalProcessLine(char* strIn)
{
	CString str, strName, strPort, strType;
	MPortDescription mpd;
	int pos;

	if(loadFromIana)
		return InternalProcessIANALine(strIn);

	str = strIn;

	pos = str.Find(_T(" "));
	if(pos<0)
		return false;

	strType = str.Left(pos);
	str     = str.Mid(pos + 1);
	strType = strType.Trim();
	str     = str.Trim();

	pos = str.Find(_T(" "));
	if(pos<0)
		return false;

	strPort = str.Left(pos);
	strName = str.Mid(pos + 1);
	strPort = strPort.Trim();
	strName = strName.Trim();

	mpd.xProto = _tstoi(strType);
	mpd.xPort  = _tstoi(strPort);
	mpd.xName  = strName;

	return Add(&mpd);
}

bool MPortDescriptionList::InternalSave(void)
{
	MPortDescription *elem;
	CString str;

	this->SortTheList();

	for(iter=theVector.begin(); iter!=theVector.end(); iter++){
		elem = *iter;
		if(elem!=NULL){
			str.Format(_T("%d %d %s"), elem->xProto, elem->xPort, elem->xName);
			if(!WriteLine(str))
				return false;
		}
	}

	return true;
}

//---------------------------------------------------------------------------

CString MPortDescriptionList::GetPortDescription(MPortDescProto typeIn, WORD portIn)
{
	MPortDescription *elem;
	CString str;
	bool found;

	found = false;
	for(iter=theVector.begin(); iter!=theVector.end() && !found; iter++){
		elem = *iter;
		if(elem!=NULL){
			if(elem->xPort==portIn && elem->xProto==(WORD)typeIn){
				str = elem->xName;
				found = true;
			}
		}
	}

	if(!found) str.Empty();

	return str;
}

//---------------------------------------------------------------------------

bool MPortDescriptionList::ImportFromIANA(CString fileNameIn)
{
	bool retVal;

	loadFromIana = true;
	retVal =  LoadFromFile(fileNameIn);
	loadFromIana = false;

	return retVal;
}

//---------------------------------------------------------------------------
